//标准对象


////为了区分对象，我们常用typeof操作符获取对象的类型，它总是返回一个字符串
console.log(typeof 451);  //number
console.log(typeof NaN);  //number
console.log(typeof 'str');  //string
console.log(typeof true);  //boolean
console.log(typeof undefined);  //undefined
console.log(typeof Math.abs);  //function
console.log(typeof null);  //object
console.log(typeof {});  //object
console.log(typeof []);  //object
////所以number，string，boolean，undefined，function，object有别于其他类型，注意null的类型是object，Array的类型也是object，所以我们用typeof无法区分null、Array和通常意义上的object---{}


//包装对象
//number、string、boolean都有包装对象，在js中，字符串也区分string类型和包装类型，包装对象用new创建
var a=new Number(123)  //123生成新的包装类型
var b=new String('str')  //'str'生成新的包装类型
var c=new Boolean(true)  //true生成新的包装类型
console.log(typeof a);
console.log(typeof b);
console.log(typeof c);
//虽然包装看起来一模一样，显示的也一模一样，但实际上他们的类型已经变成object了，所以包装对象和原始使用===会false
console.log(a===13);  //false  为什么13也会报错？
console.log(b==='str');  //false
console.log(c===true);  //false

////如果在使用Number，String，Boolean时没有用到new，会怎样？
var d=Number(333)
console.log(typeof d);   //number
var e=Boolean('true')   
console.log(typeof e);   //boolean
var e1=Boolean('false')
var e2=Boolean('')
console.log(e1);    //true,因为e1是非空字符串，所以把'false'转换为true
console.log(e2);    //因为e2是空字符串，所以false
var f=String(13.45)
console.log(typeof f);   //string



//Date
//////在JS中，Date对象表示时间和日期
var now = new Date();
console.log(now);   //Mon Nov 22 2021 11:10:28 GMT+0800 (中国标准时间)
console.log(now.getFullYear());  //年
console.log(now.getMonth());   //月
console.log(now.getDate());  //日
console.log(now.getDay());  //周几
console.log(now.getHours());  //时
console.log(now.getMinutes());  //分
console.log(now.getSeconds());  //秒
console.log(now.getMilliseconds());  //毫秒
console.log(now.getTime());   //1637551266833, 以number形式表示的时间戳
//////它表示从1970年1月1日零时整的GMT时区开始的那一刻，到现在的毫秒数。所以，时间戳可以精确地表示一个时刻，并且与时区无关。
///////当前时间是浏览器从本机系统操作获取的时间

///创建指定时间和日期
var f=new Date(2001,11,19,5,20,13,14)  //年月日时分秒毫秒
console.log(f);
/////JS里Date对象的月份值从0开始，所以0=1月，1=2月，2=3月...11=12月

//标准时间返回时间戳
var t = Date.parse('2015-06-24T19:49:22.875+08:00');
console.log(t); // 1435146562875
////但它返回的不是Date对象，而是一个时间戳。
////不过有时间戳就可以很容易地把它转换为一个Date：
var t1 = new Date(1435146562875);
console.log(t1); // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
t1.getMonth(); // 5

//////////////使用Date.parse()时传入的字符串使用实际月份01~12，转换为Date对象后getMonth()获取的月份值为0~11。


//时区
////Date对象表示的时间总是显示浏览器的系统时间，不过我们既可以显示本地时间，也可以显示调整后的UTC时间
var u=new Date()
console.log(u.getTime());
var u1=new Date(1637634116689)
console.log(u1.toLocaleString());
console.log(u1.toUTCString());


//获取当前时间戳，可用如下方法      
'use strict'
if(Date.now){
    console.log(Date.now());
}else{}
console.log(new Date().getTime());
//Date不是任意命名，必须用Date


//RegExp
//第一种是用正则表达式直接写出来，第二种是用new RegFxp表达出来
var re1 = /ABC\-001/;     //正则应该必须以  /   /  作为开头结尾吧
var re2 = new RegExp('ABC\\-001');
console.log(re1);   //  输出/ABC\-001/
console.log(re2);   //因为此时字符串的转义问题，所以此时\\为\  输出/ABC\-001/

/* 在正则表达式中，如果直接给出字符，就是精确匹配。用\d可以匹配一个数字，\w可以匹配一个字母或数字，所以：
'00\d'可以匹配'007'，但无法匹配'00A'；
'\d\d\d'可以匹配'010'；
'\w\w'可以匹配'js'；
.可以匹配任意字符，所以：
'js.'可以匹配'jsp'、'jss'、'js!'等等。
要匹配变长的字符，在正则表达式中，用*表示任意个字符（包括0个），用+表示至少一个字符，用?表示0个或1个字符，用{n}表示n个字符，用{n,m}表示n-m个字符 */

/* 进阶
要做更精确地匹配，可以用[]表示范围，比如：
[0-9a-zA-Z\_]可以匹配一个数字、字母或者下划线；   //[0-9 a-z A-Z \_]
[0-9a-zA-Z\_]+可以匹配至少由一个数字、字母或者下划线组成的字符串，比如'a100'，'0_Z'，'js2015'等等；
[a-zA-Z\_\$][0-9a-zA-Z\_\$]*可以匹配由字母或下划线、$开头，后接任意个由一个数字、字母或者下划线、$组成的字符串，也就是JavaScript允许的变量名；
[a-zA-Z\_\$][0-9a-zA-Z\_\$]{0, 19}更精确地限制了变量的长度是1-20个字符（前面1个字符+后面最多19个字符）。 */

//如何判断正则是否匹配
var re = /^\d{3}-\d{3,8}$/;   //$表示必须以$前的符号结尾，无$则对结尾没要求
console.log(re.test('020-12345'));  //true
console.log(re.test('010-123224x'));  //false
console.log(re.test('010 12345'));  //false
//RegExp对象的test()方法用于测试给定的字符串是否符合条件。


//切分字符串
////正常的切分代码
console.log('a b  c'.split(''));   //["a"," ","b"," "," ","c"]  无法切分空格
///无法连续识别空格，用正则表达式试试
console.log('a b  c'.split(/\s+/));   //["a","b","c"]
///加入逗号试试
console.log('a b , c'.split(/[\s\,]+/));   //["a", "b", "c"]
//加入分号试试
console.log('a b, c;; d;'.split(/[\s\,\;]+/));  //["a", "b", "c", "d", ""]
/////??????若上述符号放在结尾怎么说？如第三题


//分组

////正则表达式还有提取子串的强大功能，用exec()表示的就是要提取的分组
//^(\d{3})-(\d{3,8})$ 分别定义了两个组，可以直接从匹配的字符串中提取出区号和本地号码
var bc=/^(\d{3})-(\d{3,8})$/
console.log(bc.exec('010-123456'));  //['010-123456','010','123456']
console.log(bc.exec('010 123456'));  //null
//如果正则表达式定义了组，就可以在RegExp对象用exec()方法提取出子串
//ecex()在匹配成功时，就会返回一个Array，元素的第一个是正则表达式的整串字符，后面是正则表达式的子串
//ecex()在匹配失败时，会返回null

//关于提取子串的例子
var nb=/^(0[0-9]|1[0-9]|2[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$/
console.log(nb.exec('19:07:56'));  //["19:07:56", "19", "07", "56"]  这个正则表达式可以直接识别合法时间

////但有时候，正则表达式也无法做到完全验证，如日期
/*var bv=/^(0[1-9]|[1-12])\-(0[1-9]|[1-31])$/  ???????????????为何不可*/
var bv=/^(0[1-9]|1[0-2]|[0-9])\-(0[1-9]|1[0-9]|2[0-9]|3[0-1])$/
console.log(bv.exec('12-19'));   //["12-19", "12", "19"]
///对于'2-30'，'4-31'这样的非法日期，用正则还是识别不了，或者说写出来非常困难，这时就需要程序配合识别了。
console.log(bv.exec('2-30'));   //["2-30", "2", "30"]   
console.log(bv.exec('11-31'));   //["11-31", "11", "31"]  


//贪婪匹配
//例子，要匹配后面的0
var nj=/^(\d+)(0*)$/
console.log(nj.exec('124500'));  //["1234500","1234500"," "]  因为\d+采用贪婪匹配，所以会尽可能的匹配0，就把后面的0全部匹配了，而(0*)就成了空字符串
var nj1=/(\d+?)(0*)$/
console.log(nj1.exec('1234500'));  //["1234500", "12345", "00"]  必须采用非贪婪匹配才能使后面的0匹配出来，即加个？即可


//全局搜索
////全局搜索可以多次执行exec()来搜索匹配的一个字符串。当指定g标志后，每次运行exec()，正则表达式本身会更新lastIndex属性,最后匹配到指定的最后索引
var nl='obnapple,dihiapple, shdapple'
var nl1=/apple/g
console.log(nl1.exec(nl));  
console.log(nl1.lastIndex);  //8   ,匹配apple这个整体的最后一个字母的索引
console.log(nl1.exec(nl));
console.log(nl1.lastIndex);  //18
console.log(nl1.exec(nl));
console.log(nl1.lastIndex);  //28
console.log(nl1.exec(nl));
console.log(nl1.lastIndex);  //null  ，直到结束仍没有匹配到

/* 全局匹配类似搜索，因此不能使用/^...$/，那样只会最多匹配一次。  ??????????

正则表达式还可以指定i标志，表示忽略大小写，m标志，表示执行多行匹配。 */